add support for dynamic filters (#1008)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Thu, 13 Apr 2023 21:33:18 +0000 (15:33 -0600)
committerGitHub <noreply@github.com>
Thu, 13 Apr 2023 21:33:18 +0000 (15:33 -0600)
* support dynamic filters.

* delete static ResampleFilter.

* make some more filters dynamic.

* parrot Vecs::find_vec in FilterVecs::find_filter_vec.

---------

Co-authored-by: Robert Lipe <robertlipe@users.noreply.github.com>
filter_vecs.cc
filter_vecs.h
main.cc
vecs.cc
vecs.h

index 78a69a5d528d22115e16a3aa7dfc08f74fc3e177..00308b71c19714fb23f4156370fec392a8c4e6c1 100644 (file)
 #include "validate.h"       // for ValidateFilter
 #include "vecs.h"           // for Vecs
 
+template <typename T>
+Filter* fltfactory()
+{
+  static_assert(std::is_base_of<Filter, T>::value, "T must be derived from Filter");
+  return new T();
+}
 
 struct FilterVecs::Impl {
   ArcDistanceFilter arcdist;
@@ -65,19 +71,14 @@ struct FilterVecs::Impl {
   DuplicateFilter duplicate;
   HeightFilter height;
   InterpolateFilter interpolate;
-  NukeDataFilter nukedata;
   PolygonFilter polygon;
   PositionFilter position;
   RadiusFilter radius;
-  ResampleFilter resample;
   ReverseRouteFilter reverse_route;
   SimplifyRouteFilter routesimple;
-  SortFilter sort;
   StackFilter stackfilt;
   SwapDataFilter swapdata;
   TrackFilter trackfilter;
-  TransformFilter transform;
-  ValidateFilter validate;
 
   const QVector<fl_vecs_t> filter_vec_list = {
 #if FILTERS_ENABLED
@@ -107,9 +108,10 @@ struct FilterVecs::Impl {
       "Interpolate between trackpoints"
     },
     {
-      &nukedata,
+      nullptr,
       "nuketypes",
-      "Remove all waypoints, tracks, or routes"
+      "Remove all waypoints, tracks, or routes",
+      &fltfactory<NukeDataFilter>
     },
     {
       &polygon,
@@ -127,9 +129,10 @@ struct FilterVecs::Impl {
       "Include Only Points Within Radius",
     },
     {
-      &resample,
+      nullptr,
       "resample",
       "Resample Track",
+      &fltfactory<ResampleFilter>
     },
     {
       &routesimple,
@@ -137,9 +140,10 @@ struct FilterVecs::Impl {
       "Simplify routes",
     },
     {
-      &sort,
+      nullptr,
       "sort",
       "Rearrange waypoints, routes and/or tracks by resorting",
+      &fltfactory<SortFilter>
     },
     {
       &stackfilt,
@@ -157,9 +161,10 @@ struct FilterVecs::Impl {
       "Manipulate track lists"
     },
     {
-      &transform,
+      nullptr,
       "transform",
-      "Transform waypoints into a route, tracks into routes, ..."
+      "Transform waypoints into a route, tracks into routes, ...",
+      &fltfactory<TransformFilter>
     },
     {
       &height,
@@ -172,9 +177,10 @@ struct FilterVecs::Impl {
       "Swap latitude and longitude of all loaded points"
     },
     {
-      &validate,
+      nullptr,
       "validate",
-      "Validate internal data structures"
+      "Validate internal data structures",
+      &fltfactory<ValidateFilter>
     }
 #elif defined (MINIMAL_FILTERS)
     {
@@ -193,63 +199,70 @@ FilterVecs& FilterVecs::Instance()
   return instance;
 }
 
-Filter* FilterVecs::find_filter_vec(const QString& vecname)
+void FilterVecs::prepare_filter(const fltinfo_t& fltdata)
 {
-  QStringList options = vecname.split(',');
-  if (options.isEmpty()) {
-    fatal("A filter name is required.\n");
-  }
-  const QString svecname = options.takeFirst();
+  QVector<arglist_t>* args = fltdata->get_args();
 
-  for (const auto& vec : d_ptr_->filter_vec_list) {
-    if (svecname.compare(vec.name, Qt::CaseInsensitive) != 0) {
-      continue;
-    }
+  Vecs::validate_options(fltdata.options, args, fltdata.fltname);
 
-    QVector<arglist_t>* args = vec.vec->get_args();
-
-    Vecs::validate_options(options, args, vec.name);
+  /* step 1: initialize by inifile or default values */
+  if (args && !args->isEmpty()) {
+    assert(args->isDetached());
+    for (auto& arg : *args) {
+      QString qtemp = inifile_readstr(global_opts.inifile, fltdata.fltname, arg.argstring);
+      if (qtemp.isNull()) {
+        qtemp = inifile_readstr(global_opts.inifile, "Common filter settings", arg.argstring);
+      }
+      if (qtemp.isNull()) {
+        Vecs::assign_option(fltdata.fltname, &arg, arg.defaultvalue);
+      } else {
+        Vecs::assign_option(fltdata.fltname, &arg, qtemp);
+      }
+    }
+  }
 
-    /* step 1: initialize by inifile or default values */
+  /* step 2: override settings with command-line values */
+  if (!fltdata.options.isEmpty()) {
     if (args && !args->isEmpty()) {
       assert(args->isDetached());
       for (auto& arg : *args) {
-        QString qtemp = inifile_readstr(global_opts.inifile, vec.name, arg.argstring);
-        if (qtemp.isNull()) {
-          qtemp = inifile_readstr(global_opts.inifile, "Common filter settings", arg.argstring);
-        }
-        if (qtemp.isNull()) {
-          Vecs::assign_option(vec.name, &arg, arg.defaultvalue);
-        } else {
-          Vecs::assign_option(vec.name, &arg, qtemp);
+        const QString opt = Vecs::get_option(fltdata.options, arg.argstring);
+        if (!opt.isNull()) {
+          Vecs::assign_option(fltdata.fltname, &arg, opt);
         }
       }
     }
+  }
 
-    /* step 2: override settings with command-line values */
-    if (!options.isEmpty()) {
-      if (args && !args->isEmpty()) {
-        assert(args->isDetached());
-        for (auto& arg : *args) {
-          const QString opt = Vecs::get_option(options, arg.argstring);
-          if (!opt.isNull()) {
-            Vecs::assign_option(vec.name, &arg, opt);
-          }
-        }
-      }
-    }
+  if (global_opts.debug_level >= 1) {
+    Vecs::disp_vec_options(fltdata.fltname, args);
+  }
 
-    if (global_opts.debug_level >= 1) {
-      Vecs::disp_vec_options(vec.name, args);
-    }
+}
+
+FilterVecs::fltinfo_t FilterVecs::find_filter_vec(const QString& fltargstring)
+{
+  QStringList options = fltargstring.split(',');
+  if (options.isEmpty()) {
+    fatal("A filter name is required.\n");
+  }
+  const QString fltname = options.takeFirst();
 
-    return vec.vec;
+  for (const auto& vec : d_ptr_->filter_vec_list) {
+    if (fltname.compare(vec.name, Qt::CaseInsensitive) != 0) {
+      continue;
+    }
 
+    return {vec.vec, vec.name, options, vec.factory};
   }
-  return nullptr;
+
+  /*
+   * Not found.
+   */
+  return {};
 }
 
-void FilterVecs::free_filter_vec(Filter* filter)
+void FilterVecs::free_filter_vec(fltinfo_t& filter)
 {
   QVector<arglist_t>* args = filter->get_args();
 
@@ -264,24 +277,30 @@ void FilterVecs::free_filter_vec(Filter* filter)
   }
 }
 
+void FilterVecs::init_filter_vec(Filter* flt)
+{
+  QVector<arglist_t>* args = flt->get_args();
+  if (args && !args->isEmpty()) {
+    assert(args->isDetached());
+    for (auto& arg : *args) {
+      arg.argvalptr = nullptr;
+    }
+  }
+}
+
 void FilterVecs::init_filter_vecs()
 {
   for (const auto& vec : d_ptr_->filter_vec_list) {
-    QVector<arglist_t>* args = vec.vec->get_args();
-    if (args && !args->isEmpty()) {
-      assert(args->isDetached());
-      for (auto& arg : *args) {
-        arg.argvalptr = nullptr;
-      }
+    if (vec.vec != nullptr) {
+      init_filter_vec(vec.vec);
     }
   }
 }
 
-void FilterVecs::exit_filter_vecs()
+void FilterVecs::exit_filter_vec(Filter* flt)
 {
-  for (const auto& vec : d_ptr_->filter_vec_list) {
-    (vec.vec->exit)();
-    QVector<arglist_t>* args = vec.vec->get_args();
+    (flt->exit)();
+    QVector<arglist_t>* args = flt->get_args();
     if (args && !args->isEmpty()) {
       assert(args->isDetached());
       for (auto& arg : *args) {
@@ -291,6 +310,14 @@ void FilterVecs::exit_filter_vecs()
         }
       }
     }
+}
+
+void FilterVecs::exit_filter_vecs()
+{
+  for (const auto& vec : d_ptr_->filter_vec_list) {
+    if (vec.vec != nullptr) {
+      exit_filter_vec(vec.vec);
+    }
   }
 }
 
@@ -301,9 +328,10 @@ void FilterVecs::exit_filter_vecs()
 void FilterVecs::disp_filter_vecs() const
 {
   for (const auto& vec : d_ptr_->filter_vec_list) {
+    Filter* flt = (vec.factory != nullptr)? vec.factory() : vec.vec;
     printf("   %-20.20s  %-50.50s\n",
            qPrintable(vec.name), qPrintable(vec.desc));
-    const QVector<arglist_t>* args = vec.vec->get_args();
+    const QVector<arglist_t>* args = flt->get_args();
     if (args) {
       for (const auto& arg : *args) {
         if (!(arg.argtype & ARGTYPE_HIDDEN)) {
@@ -313,6 +341,9 @@ void FilterVecs::disp_filter_vecs() const
         }
       }
     }
+    if (vec.factory != nullptr) {
+      delete flt;
+    }
   }
 }
 
@@ -322,9 +353,10 @@ void FilterVecs::disp_filter_vec(const QString& vecname) const
     if (vecname.compare(vec.name, Qt::CaseInsensitive) != 0) {
       continue;
     }
+    Filter* flt = (vec.factory != nullptr)? vec.factory() : vec.vec;
     printf("   %-20.20s  %-50.50s\n",
            qPrintable(vec.name), qPrintable(vec.desc));
-    const QVector<arglist_t>* args = vec.vec->get_args();
+    const QVector<arglist_t>* args = flt->get_args();
     if (args) {
       for (const auto& arg : *args) {
         if (!(arg.argtype & ARGTYPE_HIDDEN)) {
@@ -334,6 +366,9 @@ void FilterVecs::disp_filter_vec(const QString& vecname) const
         }
       }
     }
+    if (vec.factory != nullptr) {
+      delete flt;
+    }
   }
 }
 
@@ -347,9 +382,10 @@ void FilterVecs::disp_help_url(const fl_vecs_t& vec, const arglist_t* arg)
 
 void FilterVecs::disp_v1(const fl_vecs_t& vec)
 {
+  Filter* flt = (vec.factory != nullptr)? vec.factory() : vec.vec;
   disp_help_url(vec, nullptr);
   printf("\n");
-  const QVector<arglist_t>* args = vec.vec->get_args();
+  const QVector<arglist_t>* args = flt->get_args();
   if (args) {
     for (const auto& arg : *args) {
       if (!(arg.argtype & ARGTYPE_HIDDEN)) {
@@ -366,6 +402,9 @@ void FilterVecs::disp_v1(const fl_vecs_t& vec)
       }
     }
   }
+  if (vec.factory != nullptr) {
+    delete flt;
+  }
 }
 
 /*
@@ -402,7 +441,11 @@ void FilterVecs::disp_filters(int version) const
 
 bool FilterVecs::validate_filter_vec(const fl_vecs_t& vec)
 {
-  bool ok = Vecs::validate_args(vec.name, vec.vec->get_args());
+  Filter* flt = (vec.factory != nullptr)? vec.factory() : vec.vec;
+  bool ok = Vecs::validate_args(vec.name, flt->get_args());
+  if (vec.factory != nullptr) {
+    delete flt;
+  }
 
   return ok;
 }
index 91b250b34da2fb6ff1e0acb873468532b83f5fe9..aa5323b66308273b7c38fb2c0fb916353ae9c007 100644 (file)
@@ -31,6 +31,30 @@ class FilterVecs
 {
 // Meyers Singleton
 public:
+
+  /* Types */
+
+  using FilterFactory = Filter* (*)();
+
+  class fltinfo_t {
+  public:
+
+    bool isDynamic() {
+      return factory != nullptr;
+    }
+    explicit operator bool() const {
+      return ((flt != nullptr) || (factory != nullptr));
+    }
+    Filter* operator->() const {
+      return flt;
+    }
+
+    Filter* flt{nullptr};
+    QString fltname;
+    QStringList options;
+    FilterFactory factory{nullptr};
+  };
+
   /* Special Member Functions */
 
   static FilterVecs& Instance();
@@ -41,9 +65,12 @@ public:
 
   /* Member Functions */
 
-  Filter* find_filter_vec(const QString& vecname);
-  static void free_filter_vec(Filter* filter);
+  static void prepare_filter(const fltinfo_t& fltdata);
+  fltinfo_t find_filter_vec(const QString& fltargstring);
+  static void free_filter_vec(fltinfo_t& filter);
+  static void init_filter_vec(Filter* flt);
   void init_filter_vecs();
+  static void exit_filter_vec(Filter* flt);
   void exit_filter_vecs();
   void disp_filter_vecs() const;
   void disp_filter_vec(const QString& vecname) const;
@@ -56,9 +83,10 @@ private:
   struct Impl;                   // Not defined here
 
   struct fl_vecs_t {
-    Filter* vec;
+    Filter* vec{nullptr};
     QString name;
     QString desc;
+    FilterFactory factory{nullptr};
   };
 
   /* Special Member Functions */
diff --git a/main.cc b/main.cc
index da928332eff6bf45f4020218fd184927614a2a57..d3a65301c767d300895a6c304fc1e6dedb782c52 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -301,7 +301,7 @@ run(const char* prog_name)
   int argn;
   Vecs::fmtinfo_t ivecs;
   Vecs::fmtinfo_t ovecs;
-  Filter* filter = nullptr;
+  FilterVecs::fltinfo_t filter;
   QString fname;
   QString ofname;
   int opt_version = 0;
@@ -451,10 +451,26 @@ run(const char* prog_name)
       filter = FilterVecs::Instance().find_filter_vec(argument);
 
       if (filter) {
-        filter->init();
-        filter->process();
-        filter->deinit();
-        FilterVecs::free_filter_vec(filter);
+        if (filter.isDynamic()) {
+          filter.flt = filter.factory();
+          FilterVecs::init_filter_vec(filter.flt);
+          FilterVecs::prepare_filter(filter);
+
+          filter->init();
+          filter->process();
+          filter->deinit();
+          FilterVecs::free_filter_vec(filter);
+
+          FilterVecs::exit_filter_vec(filter.flt);
+          delete filter.flt;
+          filter.flt = nullptr;
+        } else {
+          FilterVecs::prepare_filter(filter);
+          filter->init();
+          filter->process();
+          filter->deinit();
+          FilterVecs::free_filter_vec(filter);
+        }
       }  else {
         fatal("Unknown filter '%s'\n",qPrintable(argument));
       }
diff --git a/vecs.cc b/vecs.cc
index 1233a1b710e223a5c27b3d37551b72fd28e17985..d4a6fb0d1fb34408f5de6e8b763cfe8f37539d9d 100644 (file)
--- a/vecs.cc
+++ b/vecs.cc
@@ -794,7 +794,7 @@ void Vecs::validate_options(const QStringList& options, const QVector<arglist_t>
   }
 }
 
-void Vecs::prepare_format(const fmtinfo_t& fmtdata) 
+void Vecs::prepare_format(const fmtinfo_t& fmtdata)
 {
   QVector<arglist_t>* args = fmtdata->get_args();
 
diff --git a/vecs.h b/vecs.h
index fcb15ee6565767f0e73de1ee12b834b3c1a186f0..9c585d4322042eb7166302c7a6372cf3e48b1180 100644 (file)
--- a/vecs.h
+++ b/vecs.h
@@ -79,7 +79,7 @@ public:
   static void disp_vec_options(const QString& vecname, const QVector<arglist_t>* args);
   static void validate_options(const QStringList& options, const QVector<arglist_t>* args, const QString& name);
   static QString get_option(const QStringList& options, const QString& argname);
-  static void prepare_format(const fmtinfo_t& data) ;
+  static void prepare_format(const fmtinfo_t& data);
   fmtinfo_t find_vec(const QString& fmtargstring);
   void disp_vecs() const;
   void disp_vec(const QString& vecname) const;